/*
 *  原作者的代码风格和格式乃是一绝
 *  可读性相当强
 *  值得学习
 */

(function () {
  //变量声明
  var mouseFrom = {},//起点坐标
    mouseTo = {},//终点坐标
      mouseFrom1={},
    drawType = "pen", //作图的方式
    canvasObjectIndex = 0, //canvas画布内现存对象的坐标
    textbox = null; //文本框

  var fontTip =$("<textarea id='fakeTxt' rows='3' cols='20' style='color: #2B91D5; background:transparent;position:absolute;display:none;'>编辑文本之后单击鼠标</textarea>");
  $("#canvasDiv").append(fontTip);

  var objetcCount=0; //计算对象由多少个
  var objectStack = new Array();//2020年6月2日20:17:35  新加的两行


  var drawWidth = 2; //笔触宽度
  var color = "#E34F51"; //画笔颜色
  var drawingObject = null; //当前绘制对象
  var moveCount = 1; //绘制移动计数器,表示的是鼠标按下的时候移动了多少像素
  var doDrawing = false; // 绘制状态

  //初始化画板-----【存疑 2020年4月20日19:45:54】
  var canvas = new fabric.Canvas("c", {
    isDrawingMode: true,//自由绘制
    skipTargetFind: true,//整个画板元素不能被选中
    selectable: true,//元素不能被选择，不会被操作？？？【存疑】
    selection: false//画板没有被选中
    /*以上这些幺蛾子特别容易搞混  写之前必须结合API文档看清楚*/
  });

  window.canvas = canvas;
  window.zoom = window.zoom ? window.zoom : 1;//如果有缩放就缩放的意思

  canvas.freeDrawingBrush.color = color; //设置自由绘颜色,但是还没有完全实现？
  canvas.freeDrawingBrush.width = drawWidth;

  //绑定画板事件
  canvas.on("mouse:down", function (options) {
    var xy = transformMouse(options.e.offsetX, options.e.offsetY);
    //options.e.offsetX是发生点击鼠标时，在canvas元素内部的坐标
    //返回一个数对，用zoom处理偏移之后的
    mouseFrom.x = xy.x;
    mouseFrom.y = xy.y;
    mouseFrom1.x=options.e.offsetX;
    mouseFrom1.y=options.e.offsetY;
    doDrawing = true;
    console.log("From",mouseFrom.x,"offset",options.e.offsetX)
    if (drawType!="text"){
      fontTip.hide();
    }
  });

  canvas.on("mouse:up", function (options) {
    // console.log('path:created')
    var xy = transformMouse(options.e.offsetX, options.e.offsetY);
    mouseTo.x = xy.x;
    mouseTo.y = xy.y;
     //drawing();       <=================为什么把这个函数注释掉
    if(drawingObject!=null){
      objetcCount++;
      objectStack[objetcCount]=drawingObject;
      console.log("已添加对象：",objetcCount,objectStack[objetcCount]);
    }

    drawingObject = null;//当前对象置位空
    moveCount = 1;//重置计数器
    doDrawing = false;
  });

  canvas.on("path:created", function (options) {
    // objetcCount++;
    // objectStack[objetcCount]=drawingObject;
    // console.log('path:created',options.path)
    objectStack[++objetcCount]=options.path;
    console.log("已添加对象：",objetcCount,objectStack[objetcCount]);

  });

  canvas.on("mouse:move", function (options) {
    if (moveCount % 2 && !doDrawing) {
      //这只是一个简单的放错操作，和减少绘制频率无关
      return;
    }
    moveCount++;//鼠标移动一个像素就会触发一个事件，即moveCount+1
    var xy = transformMouse(options.e.offsetX, options.e.offsetY);
    mouseTo.x = xy.x;
    mouseTo.y = xy.y;
    // console.log('moving');
    drawing();//每一个像素都放入目的坐标，都进行一次drawing
  });

  canvas.on("selection:created", function (e) {//没看懂【2020年4月25日19:47:16】
    console.log("selection:created e.target._objects",e.target._objects)
    console.log("selection:created e.target",e.target)
    if (e.target._objects) {
      //多选删除
      var etCount = e.target._objects.length;
      for (var etindex = 0; etindex < etCount; etindex++) {
        canvas.remove(e.target._objects[etindex]);
      }
    } else {
      //单选删除
      canvas.remove(e.target);
    }
    canvas.discardActiveObject(); //清楚选中框
  });

  //坐标转换：
  function transformMouse(mouseX, mouseY) {
    return { x: mouseX / window.zoom, y: mouseY / window.zoom };
  }

  // jQuery("#toolsul")//其中任何元素被点到之后都会触发函数
  //   .find("li")//返回后代所有的li元素
  //   .on("click", function () {
  //     //设置样式
  //     jQuery("#toolsul")
  //       .find("li>i")//li下面的第一层的i
  //       .each(function () {//遍历每一个元素
  //         jQuery(this).attr("class", jQuery(this).attr("data-default"));//将其class设置为data-default
  //       });//遍历所有元素，使其回归默认
  //     jQuery(this)
  //       .addClass("active")//将点击的元素设置为  active——通过添加一个新的类
  //       .siblings().removeClass("active");//将所有同胞元素 移出active
  //     jQuery(this)
  //       .find("i")
  //       .attr(
  //         "class",
  //         jQuery(this)
  //           .find("i")  //获取这个元素的i类子元素的class，并把字符串中的black替换成select，在赋值给本来的class
  //           .attr("class")
  //           .replace("black", "select")
  //       );



  //绑定工具事件
  jQuery("#toolsul")//其中任何元素被点到之后都会触发函数
    .find("li")//返回后代所有的li元素
    .on("click", function () {
      //设置样式
      jQuery("#toolsul")
        .find("li>i")//li下面的第一层的i
        .each(function () {//遍历每一个元素
          jQuery(this).attr("class", jQuery(this).attr("data-default"));//将其class设置为data-default
        });//遍历所有元素，使其回归默认
      jQuery(this)
        .addClass("active")//将点击的元素设置为  active——通过添加一个新的类
        .siblings().removeClass("active");//将所有同胞元素 移出active
      jQuery(this)
        .find("i")
        .attr(
          "class",
          jQuery(this)
            .find("i")  //获取这个元素的i类子元素的class，并把字符串中的black替换成select，在赋值给本来的class
            .attr("class")
            .replace("black", "select")
        );
          
      drawType = jQuery(this).attr("data-type");//获取画图的方式
      console.log('jquery drawType',drawType)
      canvas.isDrawingMode = false;//关闭自由绘制，如果接下来是pen再打开
      if (textbox) {
        //如果还在文本编辑状态，退出文本编辑状态
        textbox.exitEditing();
        textbox = null;
      }
      if (drawType == "pen") {
        canvas.isDrawingMode = true;
      } else if (drawType == "remove") {
        canvas.selection = true;
        canvas.skipTargetFind = false;//整个画板可以被选中
        canvas.selectable = true;//控件可以选择
      } else {
        canvas.skipTargetFind = true; //画板元素不能被选中
        canvas.selection = false; //画板不显示选中
      }
    });



  //绘画方法
  function drawing() {
    // console.log('begin drawing');
    console.log('begin drawing drawingObject',drawingObject);
    if (drawingObject) {//【存疑2020年4月21日11:41:59】这算什么骚操作？
      canvas.remove(drawingObject);//如果上一次绘图残留的对象还在，就消灭掉？？
    }
    var canvasObject = null;
    console.log('drawType ',drawType);

    switch (drawType) {
      case "arrow": //箭头
        canvasObject = new fabric.Path(drawArrow(mouseFrom.x, mouseFrom.y, mouseTo.x, mouseTo.y, 30, 30), {
          stroke: color,
          fill: "rgba(255,255,255,0)",
          strokeWidth: drawWidth
        });
        break;
      case "line": //直线
        canvasObject = new fabric.Line([mouseFrom.x, mouseFrom.y, mouseTo.x, mouseTo.y], {
          stroke: color,
          strokeWidth: drawWidth
        });
        break;
      case "dottedline": //虚线
        canvasObject = new fabric.Line([mouseFrom.x, mouseFrom.y, mouseTo.x, mouseTo.y], {
          strokeDashArray: [3, 1],
          stroke: color,
          strokeWidth: drawWidth
        });
        break;
      case "circle": //正圆
        var left = mouseFrom.x,
          top = mouseFrom.y;
        var radius = Math.sqrt((mouseTo.x - left) * (mouseTo.x - left) + (mouseTo.y - top) * (mouseTo.y - top)) / 2;
        canvasObject = new fabric.Circle({
          left: left,
          top: top,
          stroke: color,
          fill: "rgba(255, 255, 255, 0)",
          radius: radius,
          strokeWidth: drawWidth
        });
        break;
      case "ellipse": //椭圆
        var left = mouseFrom.x,
          top = mouseFrom.y;
        var radius = Math.sqrt((mouseTo.x - left) * (mouseTo.x - left) + (mouseTo.y - top) * (mouseTo.y - top)) / 2;
        canvasObject = new fabric.Ellipse({
          left: left,
          top: top,
          stroke: color,
          fill: "rgba(255, 255, 255, 0)",
          originX: "center",
          originY: "center",
          rx: Math.abs(left - mouseTo.x),
          ry: Math.abs(top - mouseTo.y),
          strokeWidth: drawWidth
        });
        break;
      case "square": //TODO:正方形（后期完善）
        break;
      case "rectangle": //长方形
        var path =
          "M " +
          mouseFrom.x +" " +mouseFrom.y +
           " L " + mouseTo.x + " " + mouseFrom.y +
          " L " + mouseTo.x +" " +mouseTo.y +
          " L " + mouseFrom.x +" " +mouseTo.y +
          " L " + mouseFrom.x +" " + mouseFrom.y +
          " z";
        canvasObject = new fabric.Path(path, {
          left: left,
          top: top,
          stroke: color,
          strokeWidth: drawWidth,
          fill: "rgba(255, 255, 255, 0)"
        });
        //也可以使用fabric.Rect
        break;
      case "rightangle": //直角三角形
        var path = "M " + mouseFrom.x + " " + mouseFrom.y + " L " + mouseFrom.x + " " + mouseTo.y + " L " + mouseTo.x + " " + mouseTo.y + " z";
        canvasObject = new fabric.Path(path, {
          left: left,
          top: top,
          stroke: color,
          strokeWidth: drawWidth,
          fill: "rgba(255, 255, 255, 0)"
        });
        break;
      case "equilateral": //等边三角形
        var height = mouseTo.y - mouseFrom.y;
        canvasObject = new fabric.Triangle({
          top: mouseFrom.y,
          left: mouseFrom.x,
          width: Math.sqrt(Math.pow(height, 2) + Math.pow(height / 2.0, 2)),
          height: height,
          stroke: color,
          strokeWidth: drawWidth,
          fill: "rgba(255,255,255,0)"
        });
        break;
      case "isosceles":
        break;
      case "text"://文本框
        fontTip.show();
        var textX=mouseFrom.x;
        var textY=mouseFrom.y;
        fontTip.css({left:mouseFrom1.x,top:mouseFrom1.y});
        fontTip.width(mouseTo.x-mouseFrom.x);
        fontTip.height(mouseTo.y-mouseFrom.y);
        var words = fontTip.val().trim();//删除字符前后的空格
          if (words != "编辑文本之后单击鼠标"&&fontTip.css("display")!= "none" ){
            canvasObject = new fabric.Textbox(words, {
              left: mouseFrom.x - 60,
              top: mouseFrom.y - 20,
              width: 150,
              fontSize: 30,
              borderColor: "#2c2c2c",
              fill: "#2B91D5",
              hasControls: false
            });
            console.log("添加的文本", fontTip.css("left"),fontTip.css("top"));
            // canvas.add(textbox);
            fontTip.val("编辑文本之后单击鼠标");
            fontTip.hide();
          }

        // console.log(textbox.enterEditing())
        // textbox.hiddenTextarea.focus();
        break;
      case "remove":
        break;
      default:
        break;
    }
    // console.log('canvasObject',canvasObject)
    if (canvasObject) {
      // canvasObject.index = getCanvasObjectIndex();
      canvas.add(canvasObject); //.setActiveObject(canvasObject)
      drawingObject = canvasObject;

    }
  }

  //2020年6月2日20:39:42  添加的撤销和重做
  $(".btn-undo").on("click",function undo(){
      if(objetcCount>=1){
        canvas.remove(null);
        canvas.remove(objectStack[objetcCount--]);
        //objetcCount--;
        // console.log(objetcCount);
      }
    }
  );
  $(".btn-redo").on("click",function redo(){
      if(objetcCount<objectStack.length){
        canvas.add();
        canvas.add(objectStack[++objetcCount]);
        // console.log(objetcCount);
        //objetcCount++;
      }
    }
  );


  //绘制箭头方法，不仔细看了，就当成个轮子用吧
  function drawArrow(fromX, fromY, toX, toY, theta, headlen) {
    theta = typeof theta != "undefined" ? theta : 30;
    headlen = typeof theta != "undefined" ? headlen : 10;
    // 计算各角度和对应的P2,P3坐标
    var angle = Math.atan2(fromY - toY, fromX - toX) * 180 / Math.PI,
      angle1 = (angle + theta) * Math.PI / 180,
      angle2 = (angle - theta) * Math.PI / 180,
      topX = headlen * Math.cos(angle1),
      topY = headlen * Math.sin(angle1),
      botX = headlen * Math.cos(angle2),
      botY = headlen * Math.sin(angle2);
    var arrowX = fromX - topX,
      arrowY = fromY - topY;
    var path = " M " + fromX + " " + fromY;
    path += " L " + toX + " " + toY;
    arrowX = toX + topX;
    arrowY = toY + topY;
    path += " M " + arrowX + " " + arrowY;
    path += " L " + toX + " " + toY;
    arrowX = toX + botX;
    arrowY = toY + botY;
    path += " L " + arrowX + " " + arrowY;
    return path;
  }

  //获取画板对象的下标
  function getCanvasObjectIndex() {
    return canvasObjectIndex++;
  }
})();
